package com.rwind.dynamic.controller;

import javax.servlet.http.HttpServletRequest;

import com.rwind.dynamic.common.ApiMessageDto;
import com.rwind.dynamic.common.BizException;
import com.rwind.dynamic.common.MessageDto;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.NoHandlerFoundException;


@ControllerAdvice
public class GlobalErrorHandler {

  private static final Logger LOG = LoggerFactory.getLogger(GlobalErrorHandler.class);


  public static String getIpAddress(HttpServletRequest request) {
    String ip = request.getHeader("x-forwarded-for");
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
      ip = request.getHeader("Proxy-Client-IP");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
      ip = request.getHeader("WL-Proxy-Client-IP");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
      ip = request.getHeader("HTTP_CLIENT_IP");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
      ip = request.getHeader("HTTP_X_FORWARDED_FOR");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
      ip = request.getRemoteAddr();
    }
    return ip;
  }

  /**
   * spring.mvc.throw-exception-if-no-handler-found=true
   * @param ex
   * @param httpServletRequest
   * @return
   */
  @ExceptionHandler({NoHandlerFoundException.class})
  public ResponseEntity<MessageDto<?>> handleNoHandlerFoundException(
          NoHandlerFoundException ex, HttpServletRequest httpServletRequest) {
    MessageDto<?> response = MessageDto.getFail("404", "Resource not found");
    return ResponseEntity.status(HttpStatus.NOT_FOUND).contentType(MediaType.APPLICATION_JSON).body(response);
  }


  /**
   * 处理业务异常
   *
   * @param ex the ex
   * @return the message dto
   */
  @ExceptionHandler(BizException.class)
  @ResponseStatus(value = HttpStatus.OK)
  @ResponseBody
  public Object handleBizError(HttpServletRequest request, BizException ex) {
    LOG.info("出现业务错误,ip" + getIpAddress(request) + ",错误信息:" + ex.getMessage(), ex);
    if(this.isApiRequest(request))
      return ApiMessageDto.getFail("100",ex.getMessage());
    else
      return MessageDto.getFail("100",ex.getMessage());
  }


  /**
   * 处理参数校验异常
   */
  @ExceptionHandler(BindException.class)
  @ResponseStatus(value = HttpStatus.OK)
  @ResponseBody
  public Object handleBindError(HttpServletRequest request, BindException ex) {
    LOG.warn("出现数据校验错误,ip" + getIpAddress(request) + ",错误信息:" + ex.getMessage());
    if(this.isApiRequest(request))
      return ApiMessageDto.getFail("500", ex.getBindingResult().getFieldErrors().get(0).getDefaultMessage() );
    else
      return MessageDto.getFail("500",  ex.getBindingResult().getFieldErrors().get(0).getDefaultMessage());
  }

  /**
   * 处理参数校验异常
   */
  @ExceptionHandler(MethodArgumentNotValidException.class)
  @ResponseStatus(value = HttpStatus.OK)
  @ResponseBody
  public Object handleBindingError(HttpServletRequest request, MethodArgumentNotValidException ex) {
    LOG.warn("出现数据校验错误,ip" + getIpAddress(request) + ",错误信息:" + ex.getMessage());
    if(this.isApiRequest(request))
      return ApiMessageDto.getFail("500",  ex.getBindingResult().getFieldErrors().get(0).getDefaultMessage());
    else
      return MessageDto.getFail("500",  ex.getBindingResult().getFieldErrors().get(0).getDefaultMessage());
  }

  /**
   * 处理未知异常
   */
  @ExceptionHandler(Exception.class)
  @ResponseBody
  public Object handleUnexpectedServerError(HttpServletRequest request, Exception ex) {
    LOG.error("出现系统异常,ip：" + getIpAddress(request) + ",业务异常信息:" + ex.getMessage(), ex);
    if(this.isApiRequest(request))
      return ApiMessageDto.getFail("500", "系统异常,稍后重试");
    else
      return MessageDto.getFail("500", "系统异常,稍后重试");
  }


  private boolean isApiRequest(HttpServletRequest request) {
    return request.getRequestURI().contains("/api/");
  }

}
